/********************************Copyright (c)**********************************\
**
**                   (c) Copyright 2021, Main, China, QD.
**                           All Rights Reserved
**
**                                 By(wo4fisher)
**                           http://www.wo4fisher.com
**
**----------------------------------文件信息------------------------------------
** 文件名称: OLED.C
** 创建人员: wht
** 创建日期: 2021-06-09
** 文档描述:
**
**----------------------------------版本信息------------------------------------
** 版本代号: V0.1
** 版本说明: 初始版本
**
**------------------------------------------------------------------------------
\********************************End of Head************************************/
#include "bsp_oled.h"
#include "bsp_delay.h"
#include "zf_pca_delay.h"
#include "zf_gpio.h"
#include "intrins.h"

//OLED的显存存放格式如下
//[0]0 1 2 3 ... 127
//[1]0 1 2 3 ... 127
//[2]0 1 2 3 ... 127
//[3]0 1 2 3 ... 127
//[4]0 1 2 3 ... 127
//[5]0 1 2 3 ... 127
//[6]0 1 2 3 ... 127
//[7]0 1 2 3 ... 127

sbit OLED_SCL_SW = P2 ^ 5; //串行时钟
sbit OLED_SDA_SW = P2 ^ 4; //串行数据

#define USE_SW_IIC   1

#define HIGH 1
#define LOW  0

#define BRIGHTNESS  0xCF
#define X_WIDTH     128
#define Y_WIDTH     64

#define OLED_SCLK_Reset() OLED_SCL_SW = LOW
#define OLED_SCLK_Set() OLED_SCL_SW = HIGH

#define OLED_SDIN_Reset() OLED_SDA_SW = LOW
#define OLED_SDIN_Set() OLED_SDA_SW = HIGH

/**********************************************
//IIC Start
**********************************************/
void IIC_Start_SW()
{
    OLED_SCLK_Set();
    delayxus(1);
    OLED_SDIN_Set();
    delayxus(1);
    OLED_SDIN_Reset();
    delayxus(1);
    OLED_SCLK_Reset();
    delayxus(1);
}

/**********************************************
//IIC Stop
**********************************************/
void IIC_Stop_SW()
{
    OLED_SCLK_Reset();
    delayxus(1);
    OLED_SDIN_Reset();
    delayxus(1);
    OLED_SCLK_Set();
    delayxus(1);
    OLED_SDIN_Set();
    delayxus(1);
}

/**********************************************
// 通过I2C总线写一个字节
**********************************************/
void Write_IIC_Byte_SW ( unsigned char IIC_Byte )
{
    uint8 i;
    for ( i = 0; i < 8; i++ )
    {
        if ( IIC_Byte & 0x80 )
            OLED_SDIN_Set();
        else
            OLED_SDIN_Reset();
        delayxus(1);
        OLED_SCLK_Set();
        delayxus(1);
        OLED_SCLK_Reset();
        IIC_Byte <<= 1;
    }
    OLED_SDIN_Set();
    delayxus(1);
    OLED_SCLK_Set();
    delayxus(1);
    OLED_SCLK_Reset();
}

static void Write_IIC_Byte ( uint8 IIC_Data )
{
#if (1== USE_SW_IIC)
    Write_IIC_Byte_SW ( IIC_Data );
#else
    iic_send_data ( IIC_Data );
#endif

}
/*********************OLED写数据************************************/
static void OLED_WrDat ( uint8 IIC_Data )
{
    IIC_Start_SW();
    Write_IIC_Byte ( 0x78 );
    Write_IIC_Byte ( 0x40 );            //write data
    Write_IIC_Byte ( IIC_Data );
    IIC_Stop_SW();
}
/*********************OLED写命令************************************/
static void OLED_WrCmd ( uint8 IIC_Command )
{
    IIC_Start_SW();// IIC_Start();
    Write_IIC_Byte ( 0x78 );   //Slave address,SA0=0
    Write_IIC_Byte ( 0x00 );            //write command
    Write_IIC_Byte ( IIC_Command );
    IIC_Stop_SW();
}

/*********************OLED 设置坐标************************************/
static void OLED_Set_Pos ( uint8 x, uint8 y )
{
    x += 2; //1106
    OLED_WrCmd ( 0xb0 + y );
    OLED_WrCmd ( ( ( x & 0xf0 ) >> 4 ) | 0x10 );
    OLED_WrCmd ( ( x & 0x0f ) ); //1106  | 0x01
}
/*********************OLED全屏************************************/
void OLED_Fill ( uint8 bmp_dat )
{
    uint8 y, x;
    for ( y = 0; y < 8; y++ )
    {
        OLED_WrCmd ( 0xb0 + y );
        OLED_WrCmd ( 0x02 ); //1106 0x01
        OLED_WrCmd ( 0x10 );
        for ( x = 0; x < X_WIDTH; x++ )
            OLED_WrDat ( bmp_dat );
    }
}
/*********************OLED复位************************************/
void OLED_CLear ( void )
{
    uint8 y, x;
    for ( y = 0; y < 8; y++ )
    {
        OLED_WrCmd ( 0xb0 + y );
        OLED_WrCmd ( 0x02 ); //1106 0x01
        OLED_WrCmd ( 0x10 );
        for ( x = 0; x < X_WIDTH; x++ )
            OLED_WrDat ( 0 );
    }
}
/*********************OLED初始化************************************/
void OLED_Init ( void )
{
#if (1== USE_SW_IIC)
    gpio_pull_set ( P2_5, PULLUP );
    gpio_pull_set ( P2_4, PULLUP );
#else
    iic_init ( IIC_2, IIC2_SCL_P25, IIC2_SDA_P24, 20 );
#endif

    pca_delay_ms ( 1300 ); //初始化之前的延时很重要！
    OLED_WrCmd ( 0xae ); //--turn off oled panel
    OLED_WrCmd ( 0x02 ); //---set low column address  1106   0x00
    OLED_WrCmd ( 0x10 ); //---set high column address
    OLED_WrCmd ( 0x40 ); //--set start line address  Set Mapping RAM Display Start Line (0x00~0x3F)
    OLED_WrCmd ( 0x81 ); //--set contrast control register
    OLED_WrCmd ( BRIGHTNESS ); // Set SEG Output Current Brightness
    OLED_WrCmd ( 0xa1 ); //--Set SEG/Column Mapping     0xa0左右反置 0xa1正常
    OLED_WrCmd ( 0xc8 ); //Set COM/Row Scan Direction   0xc0上下反置 0xc8正常
    OLED_WrCmd ( 0xa6 ); //--set normal display
    OLED_WrCmd ( 0xa8 ); //--set multiplex ratio(1 to 64)
    OLED_WrCmd ( 0x3f ); //--1/64 duty
    OLED_WrCmd ( 0xd3 ); //-set display offset  Shift Mapping RAM Counter (0x00~0x3F)
    OLED_WrCmd ( 0x00 ); //-not offset
    OLED_WrCmd ( 0xd5 ); //--set display clock divide ratio/oscillator frequency
    OLED_WrCmd ( 0x80 ); //--set divide ratio, Set Clock as 100 Frames/Sec
    OLED_WrCmd ( 0xd9 ); //--set pre-charge period
    OLED_WrCmd ( 0xf1 ); //Set Pre-Charge as 15 Clocks & Discharge as 1 Clock
    OLED_WrCmd ( 0xda ); //--set com pins hardware configuration
    OLED_WrCmd ( 0x12 );
    OLED_WrCmd ( 0xdb ); //--set vcomh
    OLED_WrCmd ( 0x40 ); //Set VCOM Deselect Level
    OLED_WrCmd ( 0x20 ); //-Set Page Addressing Mode (0x00/0x01/0x02)
    OLED_WrCmd ( 0x02 ); //
    OLED_WrCmd ( 0x8d ); //--set Charge Pump enable/disable
    OLED_WrCmd ( 0x14 ); //--set(0x10) disable
    OLED_WrCmd ( 0xa4 ); // Disable Entire Display On (0xa4/0xa5)
    OLED_WrCmd ( 0xa6 ); // Disable Inverse Display On (0xa6/a7)
    OLED_WrCmd ( 0xaf ); //--turn on oled panel
    OLED_Fill ( 0x00 ); //初始清屏
    OLED_Set_Pos ( 0, 0 );
}
/***************功能描述：显示6*8一组标准ASCII字符串  显示的坐标（x,y），y为页范围0～7****************/
void OLED_PutStr6x8 ( uint8 x, y, uint8 ch[] , bit mode)
{
    uint8 c = 0, i = 0, j = 0;
    while ( ch[j] != '\0' )
    {
        c = ch[j] - 32;
        if ( x > 126 ) {
            x = 0;
            y++;
        }
        OLED_Set_Pos ( x, y );
        for ( i = 0; i < 6; i++ )
            if (mode == NOMALCOLORMODE)
                OLED_WrDat ( F6x8[c][i] );
            else
                OLED_WrDat ( ~F6x8[c][i] );
        x += 6;
        j++;
    }
}
/*******************功能描述：显示8*16一组标准ASCII字符串  显示的坐标（x,y），y为页范围0～7****************/
void OLED_PutStr8x16 ( uint8 x, y, uint8 ch[] , bit mode)
{
    uint8 c = 0, i = 0, j = 0;
    while ( ch[j] != '\0' )
    {
        c = ch[j] - 32;
        if ( x > 120 ) {
            x = 0;
            y++;
        }
        OLED_Set_Pos ( x, y );
        for ( i = 0; i < 8; i++ )
            if (mode == NOMALCOLORMODE)
                OLED_WrDat ( F8X16[c * 16 + i] );
            else
                OLED_WrDat ( ~F8X16[c * 16 + i] );
        OLED_Set_Pos ( x, y + 1 );
        for ( i = 0; i < 8; i++ )
            if (mode == NOMALCOLORMODE)
                OLED_WrDat ( F8X16[c * 16 + i + 8] );
            else
                OLED_WrDat ( ~F8X16[c * 16 + i + 8] );
        x += 8;
        j++;
    }
}
/*****************功能描述：显示16*16点阵,主要是汉字  显示的坐标（x,y），y为页范围0～7****************************/
void OLED_PutChinese ( uint8 x, y, N , bit mode)
{
    uint8 wm = 0;
    unsigned int addr = 32 * N;
    OLED_Set_Pos ( x, y );
    for ( wm = 0; wm < 16; wm++ )
    {
        if (mode == NOMALCOLORMODE)
            OLED_WrDat ( F16x16[addr] );
        else
            OLED_WrDat ( ~F16x16[addr] );
        addr += 1;
    }
    OLED_Set_Pos ( x, y + 1 );
    for ( wm = 0; wm < 16; wm++ )
    {
        if (mode == NOMALCOLORMODE)
            OLED_WrDat ( F16x16[addr] );
        else
            OLED_WrDat ( ~F16x16[addr] );
        addr += 1;
    }
}
/***********功能描述：显示显示BMP图片128×64起始点坐标(x,y),x的范围0～127，y为页的范围0～7*****************/
void OLED_Draw_BMP ( uint8 x0, y0, x1, y1, uint8 BMP[] , bit mode)
{
    unsigned int j = 0;
    uint8 x, y;

    if ( y1 % 8 == 0 ) y = y1 / 8;
    else y = y1 / 8 + 1;
    for ( y = y0; y < y1; y++ )
    {
        OLED_Set_Pos ( x0, y );
        for ( x = x0; x < x1; x++ )
        {
            if (mode == NOMALCOLORMODE)
                OLED_WrDat ( BMP[j++] );
            else
                OLED_WrDat ( ~BMP[j++] );
        }
    }
}

/********************************End of File************************************/